package cz.cuni.mff.ufal.volk.message;

import java.io.ByteArrayOutputStream;

import org.apache.log4j.Logger;

import cz.cuni.mff.ufal.volk.nabaztag.Ear;
import cz.cuni.mff.ufal.volk.nabaztag.Led;
import cz.cuni.mff.ufal.volk.nabaztag.RotationDirection;

/**
 * Auxiliary class used to build choreographies that can be sent to the Nabaztag.
 *
 * @author Bartlomiej Etenkowski
 */
public class ChoreographyBuilder {

	private static Logger log = Logger.getLogger(ChoreographyBuilder.class);

	private ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();

	/**
	 * Removes all data.
	 */
	public void clear() {
		log.trace("clear");
		outputBytes.reset();
	}

	public void appendTempo(int tempo) {
		log.trace(String.format("appendTempo(%d)", tempo));
		if (tempo < 1 || tempo > 255)
			throw new IllegalArgumentException("The tempo parameter is not between 1 and 255");
		byte[] bytes = { 0x00, 0x01, (byte)tempo };
		outputBytes.write(bytes, 0, bytes.length);
	}

	public void appendLed(int delay, Led led, int red, int green, int blue) {
		log.trace(String.format("appendLed(%d, %s, %h, %h, %h)", delay, led, red, green, blue));
		checkParameter("delay", delay, 0, 255);
		checkParameter("red", red, 0, 255);
		checkParameter("green", green, 0, 255);
		checkParameter("blue", blue, 0, 255);

		byte[] bytes = { (byte)delay, 0x07, led.getId(), (byte)red, (byte)green, (byte)blue, 0x00, 0x00 };
		outputBytes.write(bytes, 0, bytes.length);
	}

	public void appendEarPosition(int delay, Ear ear, int position, RotationDirection direction) {
		checkParameter("delay", delay, 0, 255);
		log.trace(String.format("appendEarPosition(%s, %h, %s)", ear, position, direction));
		checkParameter("position", position, 0x00, 0x12);
		byte[] bytes = { (byte)delay, 0x08, ear.getId(), (byte)position, direction.getId() };
		outputBytes.write(bytes, 0, bytes.length);
	}

	public void appendEarStep(Ear ear, int step) {
		log.trace(String.format("appendEarStep(%s, %d)", ear, step));
		checkParameter("step", step, -128, 127);
		byte[] bytes = { 0x00, 0x11, ear.getId(), (byte)step };
		outputBytes.write(bytes, 0, bytes.length);
	}

	public void appendRandomMidi(int delay) {
		log.trace(String.format("appendRandomMidi(%d)", delay));
		checkParameter("delay", delay, 0, 255);
		byte[] bytes = { (byte)delay, 0x10 };
		outputBytes.write(bytes, 0, bytes.length);
	}

	/**
	 * Transforms current choreography list into byte array that can be stored to a file
	 * and sent to the Bunny.
	 * @return
	 */
	public byte[] getBytes() {
//		return outputBytes.toByteArray();
		byte[] bytes = outputBytes.toByteArray();
		byte[] result = new byte[bytes.length + 8];
		int length = bytes.length;
		result[3] = (byte) (length & 0xff);
		length >>= 8;
		result[2] = (byte) (length & 0xff);
		length >>= 8;
		result[1] = (byte) (length & 0xff);
		length >>= 8;
		result[0] = (byte) (length & 0xff);
		for (int i = 0; i < bytes.length; i++)
			result[4 + i] = bytes[i];
		return result;
	}

	@Override
	public String toString() {
	  // TODO Auto-generated method stub
	  return super.toString();
	}

	//[start] auxiliary methods

	private static void checkParameter(String name, int value, int min, int max) {
		if (value < min || value > max)
			throw new IllegalArgumentException(String.format("The %s parameter is not between %d and %d", name, min, max));
	}

	//[end]
}
